home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / telnetd / telnetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-22  |  38.9 KB  |  1,655 lines

  1. /*
  2.  * Copyright (c) 1989, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1989, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)telnetd.c    8.4 (Berkeley) 5/30/95";
  42. #endif /* not lint */
  43.  
  44. #ifdef HAVE_CONFIG_H
  45. #include <config.h>
  46. #endif
  47.  
  48. #include "telnetd.h"
  49.  
  50. #include <paths.h>
  51.  
  52. #if    defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
  53. /*
  54.  * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
  55.  * use it to tell us to turn off all the socket security code,
  56.  * since that is only used in UNICOS 7.0 and later.
  57.  */
  58. # undef _SC_CRAY_SECURE_SYS
  59. #endif
  60.  
  61. #if    defined(_SC_CRAY_SECURE_SYS)
  62. #include <sys/sysv.h>
  63. #include <sys/secdev.h>
  64. # ifdef SO_SEC_MULTI        /* 8.0 code */
  65. #include <sys/secparm.h>
  66. #include <sys/usrv.h>
  67. # endif /* SO_SEC_MULTI */
  68. int    secflag;
  69. char    tty_dev[16];
  70. struct    secdev dv;
  71. struct    sysv sysv;
  72. # ifdef SO_SEC_MULTI        /* 8.0 code */
  73. struct    socksec ss;
  74. # else /* SO_SEC_MULTI */    /* 7.0 code */
  75. struct    socket_security ss;
  76. # endif /* SO_SEC_MULTI */
  77. #endif    /* _SC_CRAY_SECURE_SYS */
  78.  
  79. #if    defined(AUTHENTICATION)
  80. #include <libtelnet/auth.h>
  81. int    auth_level = 0;
  82. #endif
  83. #if    defined(SecurID)
  84. int    require_SecurID = 0;
  85. #endif
  86.  
  87. #ifdef HAVE_SYS_UTSNAME_H
  88. #include <sys/utsname.h>
  89. #endif
  90.  
  91. extern    int utmp_len;
  92. int    registerd_host_only = 0;
  93.  
  94. #ifdef    STREAMSPTY
  95. # include <stropts.h>
  96. # include <termio.h>
  97. /* make sure we don't get the bsd version */
  98. # include "/usr/include/sys/tty.h"
  99. # include <sys/ptyvar.h>
  100.  
  101. /*
  102.  * Because of the way ptyibuf is used with streams messages, we need
  103.  * ptyibuf+1 to be on a full-word boundary.  The following wierdness
  104.  * is simply to make that happen.
  105.  */
  106. long    ptyibufbuf[BUFSIZ/sizeof(long)+1];
  107. char    *ptyibuf = ((char *)&ptyibufbuf[1])-1;
  108. char    *ptyip = ((char *)&ptyibufbuf[1])-1;
  109. char    ptyibuf2[BUFSIZ];
  110. unsigned char ctlbuf[BUFSIZ];
  111. struct    strbuf strbufc, strbufd;
  112.  
  113. int readstream();
  114.  
  115. #else    /* ! STREAMPTY */
  116.  
  117. /*
  118.  * I/O data buffers,
  119.  * pointers, and counters.
  120.  */
  121. char    ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  122. char    ptyibuf2[BUFSIZ];
  123.  
  124. #endif /* ! STREAMPTY */
  125.  
  126. int    hostinfo = 1;            /* do we print login banner? */
  127.  
  128. #ifdef    CRAY
  129. extern int      newmap; /* nonzero if \n maps to ^M^J */
  130. int    lowpty = 0, highpty;    /* low, high pty numbers */
  131. #endif /* CRAY */
  132.  
  133. int debug = 0;
  134. int keepalive = 1;
  135. char *progname;
  136.  
  137. extern void usage P((void));
  138.  
  139. /*
  140.  * The string to pass to getopt().  We do it this way so
  141.  * that only the actual options that we support will be
  142.  * passed off to getopt().
  143.  */
  144. char valid_opts[] = {
  145.     'd', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U',
  146. #ifdef    AUTHENTICATION
  147.     'a', ':', 'X', ':',
  148. #endif
  149. #ifdef BFTPDAEMON
  150.     'B',
  151. #endif
  152. #ifdef DIAGNOSTICS
  153.     'D', ':',
  154. #endif
  155. #ifdef    ENCRYPTION
  156.     'e', ':',
  157. #endif
  158. #if    defined(CRAY) && defined(NEWINIT)
  159.     'I', ':',
  160. #endif
  161. #ifdef    LINEMODE
  162.     'l',
  163. #endif
  164. #ifdef CRAY
  165.     'r', ':',
  166. #endif
  167. #ifdef    SecurID
  168.     's',
  169. #endif
  170.     '\0'
  171. };
  172.  
  173. main(argc, argv)
  174.     char *argv[];
  175. {
  176.     struct sockaddr_in from;
  177.     int on = 1, fromlen;
  178.     register int ch;
  179.     extern char *optarg;
  180.     extern int optind;
  181. #if    defined(IPPROTO_IP) && defined(IP_TOS)
  182.     int tos = -1;
  183. #endif
  184.  
  185.     pfrontp = pbackp = ptyobuf;
  186.     netip = netibuf;
  187.     nfrontp = nbackp = netobuf;
  188. #ifdef    ENCRYPTION
  189.     nclearto = 0;
  190. #endif    /* ENCRYPTION */
  191.  
  192.     progname = *argv;
  193.  
  194. #ifdef CRAY
  195.     /*
  196.      * Get number of pty's before trying to process options,
  197.      * which may include changing pty range.
  198.      */
  199.     highpty = getnpty();
  200. #endif /* CRAY */
  201.  
  202.     while ((ch = getopt(argc, argv, valid_opts)) != EOF) {
  203.         switch(ch) {
  204.  
  205. #ifdef    AUTHENTICATION
  206.         case 'a':
  207.             /*
  208.              * Check for required authentication level
  209.              */
  210.             if (strcmp(optarg, "debug") == 0) {
  211.                 extern int auth_debug_mode;
  212.                 auth_debug_mode = 1;
  213.             } else if (strcasecmp(optarg, "none") == 0) {
  214.                 auth_level = 0;
  215.             } else if (strcasecmp(optarg, "other") == 0) {
  216.                 auth_level = AUTH_OTHER;
  217.             } else if (strcasecmp(optarg, "user") == 0) {
  218.                 auth_level = AUTH_USER;
  219.             } else if (strcasecmp(optarg, "valid") == 0) {
  220.                 auth_level = AUTH_VALID;
  221.             } else if (strcasecmp(optarg, "off") == 0) {
  222.                 /*
  223.                  * This hack turns off authentication
  224.                  */
  225.                 auth_level = -1;
  226.             } else {
  227.                 fprintf(stderr,
  228.                 "telnetd: unknown authorization level for -a\n");
  229.             }
  230.             break;
  231. #endif    /* AUTHENTICATION */
  232.  
  233. #ifdef BFTPDAEMON
  234.         case 'B':
  235.             bftpd++;
  236.             break;
  237. #endif /* BFTPDAEMON */
  238.  
  239.         case 'd':
  240.             if (strcmp(optarg, "ebug") == 0) {
  241.                 debug++;
  242.                 break;
  243.             }
  244.             usage();
  245.             /* NOTREACHED */
  246.             break;
  247.  
  248. #ifdef DIAGNOSTICS
  249.         case 'D':
  250.             /*
  251.              * Check for desired diagnostics capabilities.
  252.              */
  253.             if (!strcmp(optarg, "report")) {
  254.                 diagnostic |= TD_REPORT|TD_OPTIONS;
  255.             } else if (!strcmp(optarg, "exercise")) {
  256.                 diagnostic |= TD_EXERCISE;
  257.             } else if (!strcmp(optarg, "netdata")) {
  258.                 diagnostic |= TD_NETDATA;
  259.             } else if (!strcmp(optarg, "ptydata")) {
  260.                 diagnostic |= TD_PTYDATA;
  261.             } else if (!strcmp(optarg, "options")) {
  262.                 diagnostic |= TD_OPTIONS;
  263.             } else {
  264.                 usage();
  265.                 /* NOT REACHED */
  266.             }
  267.             break;
  268. #endif /* DIAGNOSTICS */
  269.  
  270. #ifdef    ENCRYPTION
  271.         case 'e':
  272.             if (strcmp(optarg, "debug") == 0) {
  273.                 extern int encrypt_debug_mode;
  274.                 encrypt_debug_mode = 1;
  275.                 break;
  276.             }
  277.             usage();
  278.             /* NOTREACHED */
  279.             break;
  280. #endif    /* ENCRYPTION */
  281.  
  282.         case 'h':
  283.             hostinfo = 0;
  284.             break;
  285.  
  286. #if    defined(CRAY) && defined(NEWINIT)
  287.         case 'I':
  288.             {
  289.             extern char *gen_id;
  290.             gen_id = optarg;
  291.             break;
  292.             }
  293. #endif    /* defined(CRAY) && defined(NEWINIT) */
  294.  
  295. #ifdef    LINEMODE
  296.         case 'l':
  297.             alwayslinemode = 1;
  298.             break;
  299. #endif    /* LINEMODE */
  300.  
  301.         case 'k':
  302. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  303.             lmodetype = NO_AUTOKLUDGE;
  304. #else
  305.             /* ignore -k option if built without kludge linemode */
  306. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  307.             break;
  308.  
  309.         case 'n':
  310.             keepalive = 0;
  311.             break;
  312.  
  313. #ifdef CRAY
  314.         case 'r':
  315.             {
  316.             char *strchr();
  317.             char *c;
  318.  
  319.             /*
  320.              * Allow the specification of alterations
  321.              * to the pty search range.  It is legal to
  322.              * specify only one, and not change the
  323.              * other from its default.
  324.              */
  325.             c = strchr(optarg, '-');
  326.             if (c) {
  327.                 *c++ = '\0';
  328.                 highpty = atoi(c);
  329.             }
  330.             if (*optarg != '\0')
  331.                 lowpty = atoi(optarg);
  332.             if ((lowpty > highpty) || (lowpty < 0) ||
  333.                             (highpty > 32767)) {
  334.                 usage();
  335.                 /* NOT REACHED */
  336.             }
  337.             break;
  338.             }
  339. #endif    /* CRAY */
  340.  
  341. #ifdef    SecurID
  342.         case 's':
  343.             /* SecurID required */
  344.             require_SecurID = 1;
  345.             break;
  346. #endif    /* SecurID */
  347.         case 'S':
  348. #ifdef    HAS_GETTOS
  349.             if ((tos = parsetos(optarg, "tcp")) < 0)
  350.                 fprintf(stderr, "%s%s%s\n",
  351.                     "telnetd: Bad TOS argument '", optarg,
  352.                     "'; will try to use default TOS");
  353. #else
  354.             fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
  355.                         "-S flag not supported\n");
  356. #endif
  357.             break;
  358.  
  359.         case 'u':
  360.             utmp_len = atoi(optarg);
  361.             break;
  362.  
  363.         case 'U':
  364.             registerd_host_only = 1;
  365.             break;
  366.  
  367. #ifdef    AUTHENTICATION
  368.         case 'X':
  369.             /*
  370.              * Check for invalid authentication types
  371.              */
  372.             auth_disable_name(optarg);
  373.             break;
  374. #endif    /* AUTHENTICATION */
  375.  
  376.         default:
  377.             fprintf(stderr, "telnetd: %c: unknown option\n", ch);
  378.             /* FALLTHROUGH */
  379.         case '?':
  380.             usage();
  381.             /* NOTREACHED */
  382.         }
  383.     }
  384.  
  385.     argc -= optind;
  386.     argv += optind;
  387.  
  388.     if (debug) {
  389.         int s, ns, foo;
  390.         struct servent *sp;
  391.         static struct sockaddr_in sin = { AF_INET };
  392.  
  393.         if (argc > 1) {
  394.         usage();
  395.         /* NOT REACHED */
  396.         } else if (argc == 1) {
  397.             if (sp = getservbyname(*argv, "tcp")) {
  398.             sin.sin_port = sp->s_port;
  399.             } else {
  400.             sin.sin_port = atoi(*argv);
  401.             if ((int)sin.sin_port <= 0) {
  402.                 fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
  403.                 usage();
  404.                 /* NOT REACHED */
  405.             }
  406.             sin.sin_port = htons((u_short)sin.sin_port);
  407.            }
  408.         } else {
  409.         sp = getservbyname("telnet", "tcp");
  410.         if (sp == 0) {
  411.             fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
  412.             exit(1);
  413.         }
  414.         sin.sin_port = sp->s_port;
  415.         }
  416.  
  417.         s = socket(AF_INET, SOCK_STREAM, 0);
  418.         if (s < 0) {
  419.             perror("telnetd: socket");;
  420.             exit(1);
  421.         }
  422.         (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  423.                 (char *)&on, sizeof(on));
  424.         if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
  425.         perror("bind");
  426.         exit(1);
  427.         }
  428.         if (listen(s, 1) < 0) {
  429.         perror("listen");
  430.         exit(1);
  431.         }
  432.         foo = sizeof sin;
  433.         ns = accept(s, (struct sockaddr *)&sin, &foo);
  434.         if (ns < 0) {
  435.         perror("accept");
  436.         exit(1);
  437.         }
  438.         (void) dup2(ns, 0);
  439.         (void) close(ns);
  440.         (void) close(s);
  441. #ifdef convex
  442.     } else if (argc == 1) {
  443.         ; /* VOID*/        /* Just ignore the host/port name */
  444. #endif
  445.     } else if (argc > 0) {
  446.         usage();
  447.         /* NOT REACHED */
  448.     }
  449.  
  450. #if    defined(_SC_CRAY_SECURE_SYS)
  451.     secflag = sysconf(_SC_CRAY_SECURE_SYS);
  452.  
  453.     /*
  454.      *    Get socket's security label
  455.      */
  456.     if (secflag)  {
  457.         int szss = sizeof(ss);
  458. #ifdef SO_SEC_MULTI            /* 8.0 code */
  459.         int sock_multi;
  460.         int szi = sizeof(int);
  461. #endif /* SO_SEC_MULTI */
  462.  
  463.         memset((char *)&dv, 0, sizeof(dv));
  464.  
  465.         if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
  466.             perror("getsysv");
  467.             exit(1);
  468.         }
  469.  
  470.         /*
  471.          *    Get socket security label and set device values
  472.          *       {security label to be set on ttyp device}
  473.          */
  474. #ifdef SO_SEC_MULTI            /* 8.0 code */
  475.         if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
  476.                    (char *)&ss, &szss) < 0) ||
  477.             (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
  478.                 (char *)&sock_multi, &szi) < 0)) {
  479.             perror("getsockopt");
  480.             exit(1);
  481.         } else {
  482.             dv.dv_actlvl = ss.ss_actlabel.lt_level;
  483.             dv.dv_actcmp = ss.ss_actlabel.lt_compart;
  484.             if (!sock_multi) {
  485.                 dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
  486.                 dv.dv_valcmp = dv.dv_actcmp;
  487.             } else {
  488.                 dv.dv_minlvl = ss.ss_minlabel.lt_level;
  489.                 dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
  490.                 dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
  491.             }
  492.             dv.dv_devflg = 0;
  493.         }
  494. #else /* SO_SEC_MULTI */        /* 7.0 code */
  495.         if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
  496.                 (char *)&ss, &szss) >= 0) {
  497.             dv.dv_actlvl = ss.ss_slevel;
  498.             dv.dv_actcmp = ss.ss_compart;
  499.             dv.dv_minlvl = ss.ss_minlvl;
  500.             dv.dv_maxlvl = ss.ss_maxlvl;
  501.             dv.dv_valcmp = ss.ss_maxcmp;
  502.         }
  503. #endif /* SO_SEC_MULTI */
  504.     }
  505. #endif    /* _SC_CRAY_SECURE_SYS */
  506.  
  507.     openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  508.     fromlen = sizeof (from);
  509.     if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
  510.         fprintf(stderr, "%s: ", progname);
  511.         perror("getpeername");
  512.         _exit(1);
  513.     }
  514.     if (keepalive &&
  515.         setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
  516.             (char *)&on, sizeof (on)) < 0) {
  517.         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  518.     }
  519.  
  520. #if    defined(IPPROTO_IP) && defined(IP_TOS)
  521.     {
  522. # if    defined(HAS_GETTOS)
  523.         struct tosent *tp;
  524.         if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
  525.             tos = tp->t_tos;
  526. # endif
  527.         if (tos < 0)
  528.             tos = 020;    /* Low Delay bit */
  529.         if (tos
  530.            && (setsockopt(0, IPPROTO_IP, IP_TOS,
  531.                   (char *)&tos, sizeof(tos)) < 0)
  532.            && (errno != ENOPROTOOPT) )
  533.             syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  534.     }
  535. #endif    /* defined(IPPROTO_IP) && defined(IP_TOS) */
  536.     net = 0;
  537.     doit(&from);
  538.     /* NOTREACHED */
  539. }  /* end of main */
  540.  
  541.     void
  542. usage()
  543. {
  544.     fprintf(stderr, "Usage: telnetd");
  545. #ifdef    AUTHENTICATION
  546.     fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
  547. #endif
  548. #ifdef BFTPDAEMON
  549.     fprintf(stderr, " [-B]");
  550. #endif
  551.     fprintf(stderr, " [-debug]");
  552. #ifdef DIAGNOSTICS
  553.     fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
  554. #endif
  555. #ifdef    AUTHENTICATION
  556.     fprintf(stderr, " [-edebug]");
  557. #endif
  558.     fprintf(stderr, " [-h]");
  559. #if    defined(CRAY) && defined(NEWINIT)
  560.     fprintf(stderr, " [-Iinitid]");
  561. #endif
  562. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  563.     fprintf(stderr, " [-k]");
  564. #endif
  565. #ifdef LINEMODE
  566.     fprintf(stderr, " [-l]");
  567. #endif
  568.     fprintf(stderr, " [-n]");
  569. #ifdef    CRAY
  570.     fprintf(stderr, " [-r[lowpty]-[highpty]]");
  571. #endif
  572.     fprintf(stderr, "\n\t");
  573. #ifdef    SecurID
  574.     fprintf(stderr, " [-s]");
  575. #endif
  576. #ifdef    HAS_GETTOS
  577.     fprintf(stderr, " [-S tos]");
  578. #endif
  579. #ifdef    AUTHENTICATION
  580.     fprintf(stderr, " [-X auth-type]");
  581. #endif
  582.     fprintf(stderr, " [-u utmp_hostname_length] [-U]");
  583.     fprintf(stderr, " [port]\n");
  584.     exit(1);
  585. }
  586.  
  587. /*
  588.  * getterminaltype
  589.  *
  590.  *    Ask the other end to send along its terminal type and speed.
  591.  * Output is the variable terminaltype filled in.
  592.  */
  593. static unsigned char ttytype_sbbuf[] = {
  594.     IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
  595. };
  596.  
  597.     int
  598. getterminaltype(name)
  599.     char *name;
  600. {
  601.     int retval = -1;
  602.     void _gettermname();
  603.  
  604.     settimer(baseline);
  605. #if    defined(AUTHENTICATION)
  606.     /*
  607.      * Handle the Authentication option before we do anything else.
  608.      */
  609.     send_do(TELOPT_AUTHENTICATION, 1);
  610.     while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
  611.     ttloop();
  612.     if (his_state_is_will(TELOPT_AUTHENTICATION)) {
  613.     retval = auth_wait(name);
  614.     }
  615. #endif
  616.  
  617. #ifdef    ENCRYPTION
  618.     send_will(TELOPT_ENCRYPT, 1);
  619. #endif    /* ENCRYPTION */
  620.     send_do(TELOPT_TTYPE, 1);
  621.     send_do(TELOPT_TSPEED, 1);
  622.     send_do(TELOPT_XDISPLOC, 1);
  623.     send_do(TELOPT_NEW_ENVIRON, 1);
  624.     send_do(TELOPT_OLD_ENVIRON, 1);
  625.     while (
  626. #ifdef    ENCRYPTION
  627.        his_do_dont_is_changing(TELOPT_ENCRYPT) ||
  628. #endif    /* ENCRYPTION */
  629.        his_will_wont_is_changing(TELOPT_TTYPE) ||
  630.        his_will_wont_is_changing(TELOPT_TSPEED) ||
  631.        his_will_wont_is_changing(TELOPT_XDISPLOC) ||
  632.        his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
  633.        his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
  634.     ttloop();
  635.     }
  636. #ifdef    ENCRYPTION
  637.     /*
  638.      * Wait for the negotiation of what type of encryption we can
  639.      * send with.  If autoencrypt is not set, this will just return.
  640.      */
  641.     if (his_state_is_will(TELOPT_ENCRYPT)) {
  642.     encrypt_wait();
  643.     }
  644. #endif    /* ENCRYPTION */
  645.     if (his_state_is_will(TELOPT_TSPEED)) {
  646.     static unsigned char sb[] =
  647.             { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
  648.  
  649.     memmove(nfrontp, sb, sizeof sb);
  650.     nfrontp += sizeof sb;
  651.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  652.     }
  653.     if (his_state_is_will(TELOPT_XDISPLOC)) {
  654.     static unsigned char sb[] =
  655.             { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
  656.  
  657.     memmove(nfrontp, sb, sizeof sb);
  658.     nfrontp += sizeof sb;
  659.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  660.     }
  661.     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
  662.     static unsigned char sb[] =
  663.             { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
  664.  
  665.     memmove(nfrontp, sb, sizeof sb);
  666.     nfrontp += sizeof sb;
  667.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  668.     }
  669.     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
  670.     static unsigned char sb[] =
  671.             { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
  672.  
  673.     memmove(nfrontp, sb, sizeof sb);
  674.     nfrontp += sizeof sb;
  675.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  676.     }
  677.     if (his_state_is_will(TELOPT_TTYPE)) {
  678.  
  679.     memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
  680.     nfrontp += sizeof ttytype_sbbuf;
  681.     DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
  682.                     sizeof ttytype_sbbuf - 2););
  683.     }
  684.     if (his_state_is_will(TELOPT_TSPEED)) {
  685.     while (sequenceIs(tspeedsubopt, baseline))
  686.         ttloop();
  687.     }
  688.     if (his_state_is_will(TELOPT_XDISPLOC)) {
  689.     while (sequenceIs(xdisplocsubopt, baseline))
  690.         ttloop();
  691.     }
  692.     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
  693.     while (sequenceIs(environsubopt, baseline))
  694.         ttloop();
  695.     }
  696.     if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
  697.     while (sequenceIs(oenvironsubopt, baseline))
  698.         ttloop();
  699.     }
  700.     if (his_state_is_will(TELOPT_TTYPE)) {
  701.     char first[256], last[256];
  702.  
  703.     while (sequenceIs(ttypesubopt, baseline))
  704.         ttloop();
  705.  
  706.     /*
  707.      * If the other side has already disabled the option, then
  708.      * we have to just go with what we (might) have already gotten.
  709.      */
  710.     if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
  711.         (void) strncpy(first, terminaltype, sizeof(first));
  712.         for(;;) {
  713.         /*
  714.          * Save the unknown name, and request the next name.
  715.          */
  716.         (void) strncpy(last, terminaltype, sizeof(last));
  717.         _gettermname();
  718.         if (terminaltypeok(terminaltype))
  719.             break;
  720.         if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
  721.             his_state_is_wont(TELOPT_TTYPE)) {
  722.             /*
  723.              * We've hit the end.  If this is the same as
  724.              * the first name, just go with it.
  725.              */
  726.             if (strncmp(first, terminaltype, sizeof(first)) == 0)
  727.             break;
  728.             /*
  729.              * Get the terminal name one more time, so that
  730.              * RFC1091 compliant telnets will cycle back to
  731.              * the start of the list.
  732.              */
  733.              _gettermname();
  734.             if (strncmp(first, terminaltype, sizeof(first)) != 0)
  735.             (void) strncpy(terminaltype, first, sizeof(first));
  736.             break;
  737.         }
  738.         }
  739.     }
  740.     }
  741.     return(retval);
  742. }  /* end of getterminaltype */
  743.  
  744.     void
  745. _gettermname()
  746. {
  747.     /*
  748.      * If the client turned off the option,
  749.      * we can't send another request, so we
  750.      * just return.
  751.      */
  752.     if (his_state_is_wont(TELOPT_TTYPE))
  753.     return;
  754.     settimer(baseline);
  755.     memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
  756.     nfrontp += sizeof ttytype_sbbuf;
  757.     DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
  758.                     sizeof ttytype_sbbuf - 2););
  759.     while (sequenceIs(ttypesubopt, baseline))
  760.     ttloop();
  761. }
  762.  
  763.     int
  764. terminaltypeok(s)
  765.     char *s;
  766. {
  767.     char buf[1024];
  768.  
  769.     if (terminaltype == NULL)
  770.     return(1);
  771.  
  772.     /*
  773.      * tgetent() will return 1 if the type is known, and
  774.      * 0 if it is not known.  If it returns -1, it couldn't
  775.      * open the database.  But if we can't open the database,
  776.      * it won't help to say we failed, because we won't be
  777.      * able to verify anything else.  So, we treat -1 like 1.
  778.      */
  779.     if (tgetent(buf, s) == 0)
  780.     return(0);
  781.     return(1);
  782. }
  783.  
  784. #ifndef    MAXHOSTNAMELEN
  785. #define    MAXHOSTNAMELEN 64
  786. #endif    /* MAXHOSTNAMELEN */
  787.  
  788. char *hostname;
  789. char host_name[MAXHOSTNAMELEN];
  790. char remote_host_name[MAXHOSTNAMELEN];
  791.  
  792. #ifndef    convex
  793. extern void telnet P((int, int));
  794. #else
  795. extern void telnet P((int, int, char *));
  796. #endif
  797.  
  798. /*
  799.  * Get a pty, scan input lines.
  800.  */
  801. doit(who)
  802.     struct sockaddr_in *who;
  803. {
  804.     char *host, *inet_ntoa();
  805.     int t;
  806.     struct hostent *hp;
  807.     int level;
  808.     int ptynum;
  809.     char user_name[256];
  810.  
  811.     /*
  812.      * Find an available pty to use.
  813.      */
  814. #ifndef    convex
  815.     pty = getpty(&ptynum);
  816.     if (pty < 0)
  817.         fatal(net, "All network ports in use");
  818. #else
  819.     for (;;) {
  820.         char *lp;
  821.         extern char *line, *getpty();
  822.  
  823.         if ((lp = getpty()) == NULL)
  824.             fatal(net, "Out of ptys");
  825.  
  826.         if ((pty = open(lp, 2)) >= 0) {
  827.             strcpy(line,lp);
  828.             line[5] = 't';
  829.             break;
  830.         }
  831.     }
  832. #endif
  833.  
  834. #if    defined(_SC_CRAY_SECURE_SYS)
  835.     /*
  836.      *    set ttyp line security label 
  837.      */
  838.     if (secflag) {
  839.         char slave_dev[16];
  840.  
  841.         sprintf(tty_dev, "/dev/pty/%03d", ptynum);
  842.         if (setdevs(tty_dev, &dv) < 0)
  843.              fatal(net, "cannot set pty security");
  844.         sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
  845.         if (setdevs(slave_dev, &dv) < 0)
  846.              fatal(net, "cannot set tty security");
  847.     }
  848. #endif    /* _SC_CRAY_SECURE_SYS */
  849.  
  850.     /* get name of connected client */
  851.     hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
  852.         who->sin_family);
  853.  
  854.     if (hp == NULL && registerd_host_only) {
  855.         fatal(net, "Couldn't resolve your address into a host name.\r\n\
  856.          Please contact your net administrator");
  857.     } else if (hp &&
  858.         (strlen(hp->h_name) <= (unsigned int)((utmp_len < 0) ? -utmp_len
  859.                                  : utmp_len))) {
  860.         host = hp->h_name;
  861.     } else {
  862.         host = inet_ntoa(who->sin_addr);
  863.     }
  864.     /*
  865.      * We must make a copy because Kerberos is probably going
  866.      * to also do a gethost* and overwrite the static data...
  867.      */
  868.     strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
  869.     remote_host_name[sizeof(remote_host_name)-1] = 0;
  870.     host = remote_host_name;
  871.  
  872.     (void) gethostname(host_name, sizeof (host_name));
  873.     hostname = host_name;
  874.  
  875. #if    defined(AUTHENTICATION) || defined(ENCRYPTION)
  876.     auth_encrypt_init(hostname, host, "TELNETD", 1);
  877. #endif
  878.  
  879.     init_env();
  880.     /*
  881.      * get terminal type.
  882.      */
  883.     *user_name = 0;
  884.     level = getterminaltype(user_name);
  885.     setenv("TERM", terminaltype ? terminaltype : "network", 1);
  886.  
  887.     /*
  888.      * Start up the login process on the slave side of the terminal
  889.      */
  890. #ifndef    convex
  891.     startslave(host, level, user_name);
  892.  
  893. #if    defined(_SC_CRAY_SECURE_SYS)
  894.     if (secflag) {
  895.         if (setulvl(dv.dv_actlvl) < 0)
  896.             fatal(net,"cannot setulvl()");
  897.         if (setucmp(dv.dv_actcmp) < 0)
  898.             fatal(net, "cannot setucmp()");
  899.     }
  900. #endif    /* _SC_CRAY_SECURE_SYS */
  901.  
  902.     telnet(net, pty);  /* begin server processing */
  903. #else
  904.     telnet(net, pty, host);
  905. #endif
  906.     /*NOTREACHED*/
  907. }  /* end of doit */
  908.  
  909. #if    defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
  910.     int
  911. Xterm_output(ibufp, obuf, icountp, ocount)
  912.     char **ibufp, *obuf;
  913.     int *icountp, ocount;
  914. {
  915.     int ret;
  916.     ret = term_output(*ibufp, obuf, *icountp, ocount);
  917.     *ibufp += *icountp;
  918.     *icountp = 0;
  919.     return(ret);
  920. }
  921. #define    term_output    Xterm_output
  922. #endif    /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
  923.  
  924. static FILE *_console = 0;
  925. #define  cprintf(fmt, args...) \
  926.   { if (! _console) _console = fopen ("/dev/console", "w"); \
  927.     fprintf (_console, fmt , ##args); }
  928.  
  929. /*
  930.  * Main loop.  Select from pty and network, and
  931.  * hand data to telnet receiver finite state machine.
  932.  */
  933.     void
  934. #ifndef    convex
  935. telnet(f, p)
  936. #else
  937. telnet(f, p, host)
  938. #endif
  939.     int f, p;
  940. #ifdef convex
  941.     char *host;
  942. #endif
  943. {
  944.     int on = 1;
  945. #define    TABBUFSIZ    512
  946.     char    defent[TABBUFSIZ];
  947.     char    defstrs[TABBUFSIZ];
  948. #undef    TABBUFSIZ
  949.     char *HE;
  950.     char *HN;
  951.     char *IM;
  952.     void netflush();
  953.     int nfd;
  954.  
  955.     /*
  956.      * Initialize the slc mapping table.
  957.      */
  958.     get_slc_defaults();
  959.  
  960.     /*
  961.      * Do some tests where it is desireable to wait for a response.
  962.      * Rather than doing them slowly, one at a time, do them all
  963.      * at once.
  964.      */
  965.     if (my_state_is_wont(TELOPT_SGA))
  966.         send_will(TELOPT_SGA, 1);
  967.     /*
  968.      * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
  969.      * because 4.2 clients are unable to deal with TCP urgent data.
  970.      *
  971.      * To find out, we send out a "DO ECHO".  If the remote system
  972.      * answers "WILL ECHO" it is probably a 4.2 client, and we note
  973.      * that fact ("WILL ECHO" ==> that the client will echo what
  974.      * WE, the server, sends it; it does NOT mean that the client will
  975.      * echo the terminal input).
  976.      */
  977.     send_do(TELOPT_ECHO, 1);
  978.  
  979. #ifdef    LINEMODE
  980.     if (his_state_is_wont(TELOPT_LINEMODE)) {
  981.         /* Query the peer for linemode support by trying to negotiate
  982.          * the linemode option.
  983.          */
  984.         linemode = 0;
  985.         editmode = 0;
  986.         send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
  987.     }
  988. #endif    /* LINEMODE */
  989.  
  990.     /*
  991.      * Send along a couple of other options that we wish to negotiate.
  992.      */
  993.     send_do(TELOPT_NAWS, 1);
  994.     send_will(TELOPT_STATUS, 1);
  995.     flowmode = 1;        /* default flow control state */
  996.     restartany = -1;    /* uninitialized... */
  997.     send_do(TELOPT_LFLOW, 1);
  998.  
  999.     /*
  1000.      * Spin, waiting for a response from the DO ECHO.  However,
  1001.      * some REALLY DUMB telnets out there might not respond
  1002.      * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
  1003.      * telnets so far seem to respond with WONT for a DO that
  1004.      * they don't understand...) because by the time we get the
  1005.      * response, it will already have processed the DO ECHO.
  1006.      * Kludge upon kludge.
  1007.      */
  1008.     while (his_will_wont_is_changing(TELOPT_NAWS))
  1009.         ttloop();
  1010.  
  1011.     /*
  1012.      * But...
  1013.      * The client might have sent a WILL NAWS as part of its
  1014.      * startup code; if so, we'll be here before we get the
  1015.      * response to the DO ECHO.  We'll make the assumption
  1016.      * that any implementation that understands about NAWS
  1017.      * is a modern enough implementation that it will respond
  1018.      * to our DO ECHO request; hence we'll do another spin
  1019.      * waiting for the ECHO option to settle down, which is
  1020.      * what we wanted to do in the first place...
  1021.      */
  1022.     if (his_want_state_is_will(TELOPT_ECHO) &&
  1023.         his_state_is_will(TELOPT_NAWS)) {
  1024.         while (his_will_wont_is_changing(TELOPT_ECHO))
  1025.             ttloop();
  1026.     }
  1027.     /*
  1028.      * On the off chance that the telnet client is broken and does not
  1029.      * respond to the DO ECHO we sent, (after all, we did send the
  1030.      * DO NAWS negotiation after the DO ECHO, and we won't get here
  1031.      * until a response to the DO NAWS comes back) simulate the
  1032.      * receipt of a will echo.  This will also send a WONT ECHO
  1033.      * to the client, since we assume that the client failed to
  1034.      * respond because it believes that it is already in DO ECHO
  1035.      * mode, which we do not want.
  1036.      */
  1037.     if (his_want_state_is_will(TELOPT_ECHO)) {
  1038.         DIAG(TD_OPTIONS,
  1039.             {sprintf(nfrontp, "td: simulating recv\r\n");
  1040.              nfrontp += strlen(nfrontp);});
  1041.         willoption(TELOPT_ECHO);
  1042.     }
  1043.  
  1044.     /*
  1045.      * Finally, to clean things up, we turn on our echo.  This
  1046.      * will break stupid 4.2 telnets out of local terminal echo.
  1047.      */
  1048.  
  1049.     if (my_state_is_wont(TELOPT_ECHO))
  1050.         send_will(TELOPT_ECHO, 1);
  1051.  
  1052. #ifndef    STREAMSPTY
  1053.     /*
  1054.      * Turn on packet mode
  1055.      */
  1056.     (void) ioctl(p, TIOCPKT, (char *)&on);
  1057. #endif
  1058.  
  1059. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  1060.     /*
  1061.      * Continuing line mode support.  If client does not support
  1062.      * real linemode, attempt to negotiate kludge linemode by sending
  1063.      * the do timing mark sequence.
  1064.      */
  1065.     if (lmodetype < REAL_LINEMODE)
  1066.         send_do(TELOPT_TM, 1);
  1067. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  1068.  
  1069.     /*
  1070.      * Call telrcv() once to pick up anything received during
  1071.      * terminal type negotiation, 4.2/4.3 determination, and
  1072.      * linemode negotiation.
  1073.      */
  1074.     telrcv();
  1075.  
  1076.     (void) ioctl(f, FIONBIO, (char *)&on);
  1077.     (void) ioctl(p, FIONBIO, (char *)&on);
  1078. #if    defined(CRAY2) && defined(UNICOS5)
  1079.     init_termdriver(f, p, interrupt, sendbrk);
  1080. #endif
  1081.  
  1082. #if    defined(SO_OOBINLINE)
  1083.     (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
  1084.                 (char *)&on, sizeof on);
  1085. #endif    /* defined(SO_OOBINLINE) */
  1086.  
  1087. #ifdef    SIGTSTP
  1088.     (void) signal(SIGTSTP, SIG_IGN);
  1089. #endif
  1090. #ifdef    SIGTTOU
  1091.     /*
  1092.      * Ignoring SIGTTOU keeps the kernel from blocking us
  1093.      * in ttioct() in /sys/tty.c.
  1094.      */
  1095.     (void) signal(SIGTTOU, SIG_IGN);
  1096. #endif
  1097.  
  1098.     (void) signal(SIGCHLD, cleanup);
  1099.  
  1100. #if    defined(CRAY2) && defined(UNICOS5)
  1101.     /*
  1102.      * Cray-2 will send a signal when pty modes are changed by slave
  1103.      * side.  Set up signal handler now.
  1104.      */
  1105.     if ((int)signal(SIGUSR1, termstat) < 0)
  1106.         perror("signal");
  1107.     else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
  1108.         perror("ioctl:TCSIGME");
  1109.     /*
  1110.      * Make processing loop check terminal characteristics early on.
  1111.      */
  1112.     termstat();
  1113. #endif
  1114.  
  1115. #ifdef  TIOCNOTTY
  1116.     {
  1117.         register int t;
  1118.         t = open(_PATH_TTY, O_RDWR);
  1119.         if (t >= 0) {
  1120.             (void) ioctl(t, TIOCNOTTY, (char *)0);
  1121.             (void) close(t);
  1122.         }
  1123.     }
  1124. #endif
  1125.  
  1126. #if    defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
  1127.     (void) setsid();
  1128.     ioctl(p, TIOCSCTTY, 0);
  1129. #endif
  1130.  
  1131.     /*
  1132.      * Show banner that getty never gave.
  1133.      *
  1134.      * We put the banner in the pty input buffer.  This way, it
  1135.      * gets carriage return null processing, etc., just like all
  1136.      * other pty --> client data.
  1137.      */
  1138.  
  1139. #if    !defined(CRAY) || !defined(NEWINIT)
  1140.     if (getenv("USER"))
  1141.         hostinfo = 0;
  1142. #endif
  1143.  
  1144.     if (getent(defent, "default") == 1) {
  1145.         char *getstr();
  1146.         char *cp=defstrs;
  1147.  
  1148.         HE = getstr("he", &cp);
  1149.         HN = getstr("hn", &cp);
  1150.         IM = getstr("im", &cp);
  1151.         if (HN && *HN)
  1152.             (void) strcpy(host_name, HN);
  1153.         if (IM == 0)
  1154.             IM = "";
  1155.     } else {
  1156. #ifdef HAVE_UNAME
  1157.         struct utsname u;
  1158. #endif
  1159.  
  1160. #ifdef DEFAULT_IM
  1161.         IM = DEFAULT_IM;
  1162. #else
  1163.         IM = 0;
  1164. #ifdef HAVE_UNAME
  1165.         if (uname (&u) == 0) {
  1166.             IM = malloc (strlen (UNAME_IM_PREFIX)
  1167.                      + strlen (u.sysname)
  1168.                      + 1 + strlen (u.release)
  1169.                      + strlen (UNAME_IM_SUFFIX) + 1);
  1170.             if (IM)
  1171.                 sprintf (IM, "%s%s %s%s",
  1172.                      UNAME_IM_PREFIX,
  1173.                      u.sysname, u.release,
  1174.                      UNAME_IM_SUFFIX);
  1175.         }
  1176. #endif /* HAVE_UNAME */
  1177.         if (! IM)
  1178.             IM = "\r\n\nUNIX (%h) (%t)\r\n\n";
  1179. #endif /* DEFAULT_IM */
  1180.  
  1181.         HE = 0;
  1182.     }
  1183.  
  1184.     edithost(HE, host_name);
  1185.     if (hostinfo && *IM)
  1186.         putf(IM, ptyibuf2);
  1187.  
  1188.     if (pcc)
  1189.         (void) strncat(ptyibuf2, ptyip, pcc+1);
  1190.     ptyip = ptyibuf2;
  1191.     pcc = strlen(ptyip);
  1192. #ifdef    LINEMODE
  1193.     /*
  1194.      * Last check to make sure all our states are correct.
  1195.      */
  1196.     init_termbuf();
  1197.     localstat();
  1198. #endif    /* LINEMODE */
  1199.  
  1200.     DIAG(TD_REPORT,
  1201.         {sprintf(nfrontp, "td: Entering processing loop\r\n");
  1202.          nfrontp += strlen(nfrontp);});
  1203.  
  1204. #ifdef    convex
  1205.     startslave(host);
  1206. #endif
  1207.  
  1208.     nfd = ((f > p) ? f : p) + 1;
  1209.     for (;;) {
  1210.         fd_set ibits, obits, xbits;
  1211.         register int c;
  1212.  
  1213.         if (ncc < 0 && pcc < 0)
  1214.           { cprintf ("Breaking because NCC = %d, PCC = %d\n", ncc, pcc);
  1215.             break;
  1216.           }
  1217.  
  1218. #if    defined(CRAY2) && defined(UNICOS5)
  1219.         if (needtermstat)
  1220.             _termstat();
  1221. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1222.         FD_ZERO(&ibits);
  1223.         FD_ZERO(&obits);
  1224.         FD_ZERO(&xbits);
  1225.         /*
  1226.          * Never look for input if there's still
  1227.          * stuff in the corresponding output buffer
  1228.          */
  1229.         if (nfrontp - nbackp || pcc > 0) {
  1230.             FD_SET(f, &obits);
  1231.         } else {
  1232.             FD_SET(p, &ibits);
  1233.         }
  1234.         if (pfrontp - pbackp || ncc > 0) {
  1235.             FD_SET(p, &obits);
  1236.         } else {
  1237.             FD_SET(f, &ibits);
  1238.         }
  1239.         if (!SYNCHing) {
  1240.             FD_SET(f, &xbits);
  1241.         }
  1242.         if ((c = select(nfd, &ibits, &obits, &xbits,
  1243.                         (struct timeval *)0)) < 1) {
  1244.             if (c == -1) {
  1245.                 if (errno == EINTR) {
  1246.                     continue;
  1247.                 }
  1248.             }
  1249.             sleep(5);
  1250.             continue;
  1251.         }
  1252.  
  1253.         /*
  1254.          * Any urgent data?
  1255.          */
  1256.         if (FD_ISSET(net, &xbits)) {
  1257.             SYNCHing = 1;
  1258.         }
  1259.  
  1260.         /*
  1261.          * Something to read from the network...
  1262.          */
  1263.         if (FD_ISSET(net, &ibits)) {
  1264. #if    !defined(SO_OOBINLINE)
  1265.             /*
  1266.              * In 4.2 (and 4.3 beta) systems, the
  1267.              * OOB indication and data handling in the kernel
  1268.              * is such that if two separate TCP Urgent requests
  1269.              * come in, one byte of TCP data will be overlaid.
  1270.              * This is fatal for Telnet, but we try to live
  1271.              * with it.
  1272.              *
  1273.              * In addition, in 4.2 (and...), a special protocol
  1274.              * is needed to pick up the TCP Urgent data in
  1275.              * the correct sequence.
  1276.              *
  1277.              * What we do is:  if we think we are in urgent
  1278.              * mode, we look to see if we are "at the mark".
  1279.              * If we are, we do an OOB receive.  If we run
  1280.              * this twice, we will do the OOB receive twice,
  1281.              * but the second will fail, since the second
  1282.              * time we were "at the mark", but there wasn't
  1283.              * any data there (the kernel doesn't reset
  1284.              * "at the mark" until we do a normal read).
  1285.              * Once we've read the OOB data, we go ahead
  1286.              * and do normal reads.
  1287.              *
  1288.              * There is also another problem, which is that
  1289.              * since the OOB byte we read doesn't put us
  1290.              * out of OOB state, and since that byte is most
  1291.              * likely the TELNET DM (data mark), we would
  1292.              * stay in the TELNET SYNCH (SYNCHing) state.
  1293.              * So, clocks to the rescue.  If we've "just"
  1294.              * received a DM, then we test for the
  1295.              * presence of OOB data when the receive OOB
  1296.              * fails (and AFTER we did the normal mode read
  1297.              * to clear "at the mark").
  1298.              */
  1299.             if (SYNCHing) {
  1300.             int atmark;
  1301.  
  1302.             (void) ioctl(net, SIOCATMARK, (char *)&atmark);
  1303.             if (atmark) {
  1304.                 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
  1305.                 if ((ncc == -1) && (errno == EINVAL)) {
  1306.                 ncc = read(net, netibuf, sizeof (netibuf));
  1307.                 if (sequenceIs(didnetreceive, gotDM)) {
  1308.                     SYNCHing = stilloob(net);
  1309.                 }
  1310.                 }
  1311.             } else {
  1312.                 ncc = read(net, netibuf, sizeof (netibuf));
  1313.             }
  1314.             } else {
  1315.             ncc = read(net, netibuf, sizeof (netibuf));
  1316.             }
  1317.             settimer(didnetreceive);
  1318. #else    /* !defined(SO_OOBINLINE)) */
  1319.             ncc = read(net, netibuf, sizeof (netibuf));
  1320. #endif    /* !defined(SO_OOBINLINE)) */
  1321.             if (ncc < 0 && errno == EWOULDBLOCK)
  1322.             ncc = 0;
  1323.             else {
  1324.             if (ncc <= 0) {
  1325.               cprintf ("Breaking because NCC = %d: %s\n", ncc,
  1326.                    strerror (errno));
  1327.                 break;
  1328.             }
  1329.             netip = netibuf;
  1330.             }
  1331.             DIAG((TD_REPORT | TD_NETDATA),
  1332.                 {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
  1333.                  nfrontp += strlen(nfrontp);});
  1334.             DIAG(TD_NETDATA, printdata("nd", netip, ncc));
  1335.         }
  1336.  
  1337.         /*
  1338.          * Something to read from the pty...
  1339.          */
  1340.         if (FD_ISSET(p, &ibits)) {
  1341. #ifndef    STREAMSPTY
  1342.             pcc = read(p, ptyibuf, BUFSIZ);
  1343. #else
  1344.             pcc = readstream(p, ptyibuf, BUFSIZ);
  1345. #endif
  1346.             /*
  1347.              * On some systems, if we try to read something
  1348.              * off the master side before the slave side is
  1349.              * opened, we get EIO.
  1350.              */
  1351.             if (pcc < 0 && (errno == EWOULDBLOCK ||
  1352. #ifdef    EAGAIN
  1353.                     errno == EAGAIN ||
  1354. #endif
  1355.                     errno == EIO)) {
  1356.                 pcc = 0;
  1357.             } else {
  1358.                 if (pcc <= 0)
  1359.                   { 
  1360.                     cprintf ("Breaking because PCC = %d\n", pcc);
  1361.                     break;
  1362.                   }
  1363. #if    !defined(CRAY2) || !defined(UNICOS5)
  1364. #ifdef    LINEMODE
  1365.                 /*
  1366.                  * If ioctl from pty, pass it through net
  1367.                  */
  1368.                 if (ptyibuf[0] & TIOCPKT_IOCTL) {
  1369.                     copy_termbuf(ptyibuf+1, pcc-1);
  1370.                     localstat();
  1371.                     pcc = 1;
  1372.                 }
  1373. #endif    /* LINEMODE */
  1374.                 if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
  1375.                     netclear();    /* clear buffer back */
  1376. #ifndef    NO_URGENT
  1377.                     /*
  1378.                      * There are client telnets on some
  1379.                      * operating systems get screwed up
  1380.                      * royally if we send them urgent
  1381.                      * mode data.
  1382.                      */
  1383.                     *nfrontp++ = IAC;
  1384.                     *nfrontp++ = DM;
  1385.                     neturg = nfrontp-1; /* off by one XXX */
  1386.                     DIAG(TD_OPTIONS,
  1387.                         printoption("td: send IAC", DM));
  1388.  
  1389. #endif
  1390.                 }
  1391.                 if (his_state_is_will(TELOPT_LFLOW) &&
  1392.                     (ptyibuf[0] &
  1393.                      (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
  1394.                     int newflow =
  1395.                         ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
  1396.                     if (newflow != flowmode) {
  1397.                         flowmode = newflow;
  1398.                         (void) sprintf(nfrontp,
  1399.                             "%c%c%c%c%c%c",
  1400.                             IAC, SB, TELOPT_LFLOW,
  1401.                             flowmode ? LFLOW_ON
  1402.                                  : LFLOW_OFF,
  1403.                             IAC, SE);
  1404.                         nfrontp += 6;
  1405.                         DIAG(TD_OPTIONS, printsub('>',
  1406.                             (unsigned char *)nfrontp-4,
  1407.                             4););
  1408.                     }
  1409.                 }
  1410.                 pcc--;
  1411.                 ptyip = ptyibuf+1;
  1412. #else    /* defined(CRAY2) && defined(UNICOS5) */
  1413.                 if (!uselinemode) {
  1414.                     unpcc = pcc;
  1415.                     unptyip = ptyibuf;
  1416.                     pcc = term_output(&unptyip, ptyibuf2,
  1417.                                 &unpcc, BUFSIZ);
  1418.                     ptyip = ptyibuf2;
  1419.                 } else
  1420.                     ptyip = ptyibuf;
  1421. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1422.             }
  1423.         }
  1424.  
  1425.         while (pcc > 0) {
  1426.             if ((&netobuf[BUFSIZ] - nfrontp) < 2)
  1427.                 break;
  1428.             c = *ptyip++ & 0377, pcc--;
  1429.             if (c == IAC)
  1430.                 *nfrontp++ = c;
  1431. #if    defined(CRAY2) && defined(UNICOS5)
  1432.             else if (c == '\n' &&
  1433.                      my_state_is_wont(TELOPT_BINARY) && newmap)
  1434.                 *nfrontp++ = '\r';
  1435. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1436.             *nfrontp++ = c;
  1437.             if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
  1438.                 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
  1439.                     *nfrontp++ = *ptyip++ & 0377;
  1440.                     pcc--;
  1441.                 } else
  1442.                     *nfrontp++ = '\0';
  1443.             }
  1444.         }
  1445. #if    defined(CRAY2) && defined(UNICOS5)
  1446.         /*
  1447.          * If chars were left over from the terminal driver,
  1448.          * note their existence.
  1449.          */
  1450.         if (!uselinemode && unpcc) {
  1451.             pcc = unpcc;
  1452.             unpcc = 0;
  1453.             ptyip = unptyip;
  1454.         }
  1455. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1456.  
  1457.         if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
  1458.             netflush();
  1459.         if (ncc > 0)
  1460.             telrcv();
  1461.         if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
  1462.             ptyflush();
  1463.     }
  1464.     cleanup(0);
  1465. }  /* end of telnet */
  1466.     
  1467. #ifndef    TCSIG
  1468. # ifdef    TIOCSIG
  1469. #  define TCSIG TIOCSIG
  1470. # endif
  1471. #endif
  1472.  
  1473. #ifdef    STREAMSPTY
  1474.  
  1475. int flowison = -1;  /* current state of flow: -1 is unknown */
  1476.  
  1477. int readstream(p, ibuf, bufsize)
  1478.     int p;
  1479.     char *ibuf;
  1480.     int bufsize;
  1481. {
  1482.     int flags = 0;
  1483.     int ret = 0;
  1484.     struct termios *tsp;
  1485.     struct termio *tp;
  1486.     struct iocblk *ip;
  1487.     char vstop, vstart;
  1488.     int ixon;
  1489.     int newflow;
  1490.  
  1491.     strbufc.maxlen = BUFSIZ;
  1492.     strbufc.buf = (char *)ctlbuf;
  1493.     strbufd.maxlen = bufsize-1;
  1494.     strbufd.len = 0;
  1495.     strbufd.buf = ibuf+1;
  1496.     ibuf[0] = 0;
  1497.  
  1498.     ret = getmsg(p, &strbufc, &strbufd, &flags);
  1499.     if (ret < 0)  /* error of some sort -- probably EAGAIN */
  1500.         return(-1);
  1501.  
  1502.     if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
  1503.         /* data message */
  1504.         if (strbufd.len > 0) {            /* real data */
  1505.             return(strbufd.len + 1);    /* count header char */
  1506.         } else {
  1507.             /* nothing there */
  1508.             errno = EAGAIN;
  1509.             return(-1);
  1510.         }
  1511.     }
  1512.  
  1513.     /*
  1514.      * It's a control message.  Return 1, to look at the flag we set
  1515.      */
  1516.  
  1517.     switch (ctlbuf[0]) {
  1518.     case M_FLUSH:
  1519.         if (ibuf[1] & FLUSHW)
  1520.             ibuf[0] = TIOCPKT_FLUSHWRITE;
  1521.         return(1);
  1522.  
  1523.     case M_IOCTL:
  1524.         ip = (struct iocblk *) (ibuf+1);
  1525.  
  1526.         switch (ip->ioc_cmd) {
  1527.         case TCSETS:
  1528.         case TCSETSW:
  1529.         case TCSETSF:
  1530.             tsp = (struct termios *)
  1531.                     (ibuf+1 + sizeof(struct iocblk));
  1532.             vstop = tsp->c_cc[VSTOP];
  1533.             vstart = tsp->c_cc[VSTART];
  1534.             ixon = tsp->c_iflag & IXON;
  1535.             break;
  1536.         case TCSETA:
  1537.         case TCSETAW:
  1538.         case TCSETAF:
  1539.             tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
  1540.             vstop = tp->c_cc[VSTOP];
  1541.             vstart = tp->c_cc[VSTART];
  1542.             ixon = tp->c_iflag & IXON;      
  1543.             break;
  1544.         default:
  1545.             errno = EAGAIN;
  1546.             return(-1);
  1547.         }
  1548.  
  1549.         newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
  1550.         if (newflow != flowison) {  /* it's a change */
  1551.             flowison = newflow;
  1552.             ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
  1553.             return(1);
  1554.         }
  1555.     }
  1556.  
  1557.     /* nothing worth doing anything about */
  1558.     errno = EAGAIN;
  1559.     return(-1);
  1560. }
  1561. #endif /* STREAMSPTY */
  1562.  
  1563. /*
  1564.  * Send interrupt to process on other side of pty.
  1565.  * If it is in raw mode, just write NULL;
  1566.  * otherwise, write intr char.
  1567.  */
  1568.     void
  1569. interrupt()
  1570. {
  1571.     ptyflush();    /* half-hearted */
  1572.  
  1573. #if defined(STREAMSPTY) && defined(TIOCSIGNAL)
  1574.     /* Streams PTY style ioctl to post a signal */
  1575.     {
  1576.         int sig = SIGINT;
  1577.         (void) ioctl(pty, TIOCSIGNAL, &sig);
  1578.         (void) ioctl(pty, I_FLUSH, FLUSHR);
  1579.     }
  1580. #else
  1581. #ifdef    TCSIG
  1582.     (void) ioctl(pty, TCSIG, (char *)SIGINT);
  1583. #else    /* TCSIG */
  1584.     init_termbuf();
  1585.     *pfrontp++ = slctab[SLC_IP].sptr ?
  1586.             (unsigned char)*slctab[SLC_IP].sptr : '\177';
  1587. #endif    /* TCSIG */
  1588. #endif
  1589. }
  1590.  
  1591. /*
  1592.  * Send quit to process on other side of pty.
  1593.  * If it is in raw mode, just write NULL;
  1594.  * otherwise, write quit char.
  1595.  */
  1596.     void
  1597. sendbrk()
  1598. {
  1599.     ptyflush();    /* half-hearted */
  1600. #ifdef    TCSIG
  1601.     (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
  1602. #else    /* TCSIG */
  1603.     init_termbuf();
  1604.     *pfrontp++ = slctab[SLC_ABORT].sptr ?
  1605.             (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
  1606. #endif    /* TCSIG */
  1607. }
  1608.  
  1609.     void
  1610. sendsusp()
  1611. {
  1612. #ifdef    SIGTSTP
  1613.     ptyflush();    /* half-hearted */
  1614. # ifdef    TCSIG
  1615.     (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
  1616. # else    /* TCSIG */
  1617.     *pfrontp++ = slctab[SLC_SUSP].sptr ?
  1618.             (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
  1619. # endif    /* TCSIG */
  1620. #endif    /* SIGTSTP */
  1621. }
  1622.  
  1623. /*
  1624.  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
  1625.  * just send back "[Yes]".
  1626.  */
  1627.     void
  1628. recv_ayt()
  1629. {
  1630. #if    defined(SIGINFO) && defined(TCSIG)
  1631.     if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
  1632.         (void) ioctl(pty, TCSIG, (char *)SIGINFO);
  1633.         return;
  1634.     }
  1635. #endif
  1636.     (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
  1637.     nfrontp += 9;
  1638. }
  1639.  
  1640.     void
  1641. doeof()
  1642. {
  1643.     init_termbuf();
  1644.  
  1645. #if    defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
  1646.     if (!tty_isediting()) {
  1647.         extern char oldeofc;
  1648.         *pfrontp++ = oldeofc;
  1649.         return;
  1650.     }
  1651. #endif
  1652.     *pfrontp++ = slctab[SLC_EOF].sptr ?
  1653.             (unsigned char)*slctab[SLC_EOF].sptr : '\004';
  1654. }
  1655.